package ctu.edu.vn.musicmanager.business;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;
import javax.jms.Topic;
import javax.jms.TopicConnection;
import javax.jms.TopicConnectionFactory;
import javax.jms.TopicPublisher;
import javax.jms.TopicSession;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import java.util.Properties;
import java.util.Vector;




public class MusicManagerServer implements MessageListener {
	public final int Accepted_code = 1;
	public final int Denied_code = 0;
	
	public static void main(String[] args) {
		try {
			new MusicManagerServer();
		} catch (NamingException | JMSException e) {
			e.printStackTrace();
		}
	}
	
	private class Queue extends Thread implements Runnable {

		public Queue() {
			super(new Thread());
		}

		@Override
		public void run() {
			while (true) {
				if (!curQueue.isEmpty()) {
					String front = curQueue.elementAt(0);
					curQueue.remove(0);
					// Xuất tạm message đang trong xử lí
					//System.out.println("Queue 's mess: " + front);
					// Tách dữ liệu từ dữ dữ liệu gốc
					Vector<Vector<String>> mess = Split(front);
					Vector<String> header = mess.get(0);
					// Xử lí dữ liệu
					
					// 0 : xử lí yêu cầu kết nối và cấp phát ID
					if (header.get(0).equals("0")) {
						// Tạo dữ liệu trả v�?
						String res_mess = header.get(0);

						if (curUsers < limitUsers) {
							res_mess += Accepted_code + ":" + header.get(1) + ":" + curIDUsers;
							curIDUsers++;
							curUsers++;
						} else {
							res_mess += Denied_code + ":" + header.get(1) + ":"
									+ msCRUD.overload_user;
						}

						// Trả dữ liệu cho client
						sendMessage(res_mess);
					} else {
						if (header.get(0).equals("1")) {
							
							// Lấy thông tin từ dữ liệu nhận
							int number = Integer.parseInt(header.get(1));
							String ID_Sender = header.get(2);

							// Dòng thao tác hiện tại
							Vector<String> curLine;

							// Tao dữ liệu trả v�? : thành công - thất bại
							String succ_mess = "", fail_mess = "";

							// Biến đếm lượng file thêm thành công
							int succ_counting = 0;

							for (int i = 1; i <= number; i++) {

								curLine = mess.get(i);
								
								// Tiến hành thêm file nhạc và lấy mã lỗi (nếu
								// có) trả v�?
								int res = msCRUD.addSong(curLine.get(0),
										curLine.get(1), curLine.get(2));
								
								// Thao tác thêm thành công : (res >= 0) -> res
								// là ID của file vừa thêm
								// Thao tác thêm thất bại : (res < 0) -> |res|
								// là mã lỗi khi thêm
								if (res >= 0) {
									if (succ_mess.length() > 0)
										succ_mess += "\n";

									succ_mess += res + ":" + curLine.get(0)
											+ ":" + curLine.get(1);
									succ_counting++;
								} else {
									if (fail_mess.length() > 0)
										fail_mess += "\n";

									// Lấy mã lỗi bằng trị tuyệt đối
									res = -res;
									if (res < 10)
										fail_mess += "0";
									fail_mess += res + ":" + curLine.get(0)
											+ ":" + curLine.get(1);
								}

							}
							// Tạo và gữi bộ dữ liệu thành công
							if (succ_counting > 0) {
								succ_mess = header.get(0) + Accepted_code + ":"
										+ succ_counting + ":" + ID_Sender+ "\n" + succ_mess;
								sendMessage(succ_mess);
							}
							// Tạo và gữi bộ dữ liệu thất bại
							if (succ_counting < number) {
								fail_mess = header.get(0) + Denied_code + ":"
										+ (number - succ_counting) + ":"
										+ ID_Sender + "\n"
										+ fail_mess;
								sendMessage(fail_mess);
							}

						} else if (header.get(0).equals("2")) {

							// Lấy thông tin từ dữ liệu nhận
							int number = Integer.parseInt(header.get(1));
							String ID_Sender = header.get(2);
							
							// Dòng thao tác hiện tại
							Vector<String> curLine;

							// Tao dữ liệu trả v�? : thành công - thất bại
							String succ_mess = "", fail_mess = "";

							// Biến đếm lượng file thêm thành công
							int succ_counting = 0;

							for (int i = 1; i <= number; i++) {

								curLine = mess.get(i);

								// Tiến hành sửa thông tin file nhạc và lấy mã
								// lỗi (nếu
								// có) trả v�?
								int res = msCRUD.editSong(
										Integer.parseInt(curLine.get(0)),
										curLine.get(1));

								// Thao tác sửa thành công : (res = 0)
								// Thao tác sửa thất bại : (res < 0) -> |res|
								// là mã lỗi khi sửa thông tin
								if (res == 0) {
									if (succ_mess.length() > 0)
										succ_mess += "\n";

									succ_mess += curLine.get(0) + ":"
											+ curLine.get(1);
									succ_counting++;
								} else {
									if (fail_mess.length() > 0)
										fail_mess += "\n";

									// Lấy mã lỗi bằng trị tuyệt đối
									res = -res;
									if (res < 10)
										fail_mess += "0";
									fail_mess += res + ":" + curLine.get(0)
											+ ":" + curLine.get(1);
								}

							}
							// Tạo và gữi bộ dữ liệu thành công
							if (succ_counting > 0) {
								succ_mess = header.get(0) + Accepted_code + ":"
										+ succ_counting + ":" + ID_Sender + "\n" + succ_mess;
								sendMessage(succ_mess);
							}
							// Tạo và gữi bộ dữ liệu thất bại
							if (succ_counting < number) {
								fail_mess = header.get(0) + Denied_code + ":"
										+ (number - succ_counting) + ":"
										+ ID_Sender + "\n"
										+ fail_mess;
								sendMessage(fail_mess);
							}

						} else if (header.get(0).equals("3")) {
							// Lấy thông tin từ dữ liệu nhận
							int number = Integer.parseInt(header.get(1));
							String ID_Sender = header.get(2);

							// Dòng thao tác hiện tại
							Vector<String> curLine;

							// Tao dữ liệu trả v�? : thành công - thất bại
							String succ_mess = "", fail_mess = "";

							// Biến đếm lượng file thêm thành công
							int succ_counting = 0;

							for (int i = 1; i <= number; i++) {

								curLine = mess.get(i);

								// Tiến hành xóa file nhạc và lấy mã lỗi (nếu
								// có) trả v�?
								int res = msCRUD.deleteSong(Integer
										.parseInt(curLine.get(0)));

								// Thao tác xóa thành công : (res = 0)
								// Thao tác xóa thất bại : (res < 0) -> |res|
								// là mã lỗi khi xóa file nhạc
								if (res == 0) {
									if (succ_mess.length() > 0)
										succ_mess += "\n";

									succ_mess += curLine.get(0);
									succ_counting++;
								} else {
									if (fail_mess.length() > 0)
										fail_mess += "\n";

									// Lấy mã lỗi bằng trị tuyệt đối
									res = -res;
									if (res < 10)
										fail_mess += "0";
									fail_mess += res + ":" + curLine.get(0);
								}

							}
							// Tạo và gữi bộ dữ liệu thành công
							if (succ_counting > 0) {
								succ_mess = header.get(0) + Accepted_code + ":"
										+ succ_counting + ":" + ID_Sender + "\n" + succ_mess;
								sendMessage(succ_mess);
							}
							// Tạo và gữi bộ dữ liệu thất bại
							if (succ_counting < number) {
								fail_mess = header.get(0) + Denied_code + ":"
										+ (number - succ_counting) + ":"
										+ ID_Sender + "\n"
										+ fail_mess;
								sendMessage(fail_mess);
							}
						} else if (header.get(0).equals("4")) {
							// Lấy thông tin từ dữ liệu nhận
							String ID_Sender = header.get(1);

							// Tiến hành lấy danh sách bài hát, danh sách tên sẽ
							// được lưu vào SongNames, danh sách ID sẽ được lưu
							// SongIDs, danh sách �?ịnh dạng sẽ được lưu vào
							// SongFormat
							Vector<Integer> SongIDs = new Vector<Integer>();
							Vector<String> SongNames = new Vector<String>();
							Vector<String> SongFormats = new Vector<String>();
							int res = msCRUD.getSongs(SongIDs, SongNames,
									SongFormats);

							// Tao dữ liệu trả v�? : thành công - thất bại
							String res_mess = "";

							if (res == 0) {
								res_mess = header.get(0) + Accepted_code + ":"
										+ SongNames.size() + ":" + ID_Sender;
								for (int i = 0; i < SongNames.size(); i++) {
									res_mess += "\n" + SongIDs.get(i) + ":"
											+ SongNames.get(i) + ":"
											+ SongFormats.get(i);
								}
								//System.out.println(res_mess);
								sendMessage(res_mess);
							} else {
								res_mess = header.get(0) + Denied_code + ":";
								// Lấy mã lỗi bằng trị tuyệt đối
								res = -res;
								if (res < 10)
									res_mess += "0";
								res_mess += res + ":" + ID_Sender;
								sendMessage(res_mess);
							}

						} else if (header.get(0).equals("5")) {
							// Lấy thông tin từ dữ liệu nhận
							// String ID_Sender = header.get(1);
							// String STT_Req = header.get(2);
							curUsers--;
						} else {
							// Sai định dạng, không làm gì cả

						}
					}
				}
			}
		}
	}

	TopicPublisher topicPublisher;
	private int curUsers;
	private int curIDUsers;
	private final int limitUsers = 10;
	private MusicCRUD msCRUD;

	private Topic topicSender;
	private TopicSession topicSession;
	private Vector<String> curQueue;

	/**
	 * Create the frame.
	 * 
	 * @throws NamingException
	 * @throws JMSException
	 */
	public MusicManagerServer() throws NamingException, JMSException {

		
		curQueue = new Vector<String>();
		curUsers = 0;
		curIDUsers = 0;
		msCRUD = new MusicCRUD();

		Context context = getContext();
		TopicConnectionFactory topicConnectionFactory = (TopicConnectionFactory) context
				.lookup("ConnectionFactory");
		topicSender = (Topic) context.lookup("topic/JMSServerSender");
		TopicConnection topicConnection = (TopicConnection) topicConnectionFactory
				.createTopicConnection();
		topicSession = topicConnection.createTopicSession(false,
				TopicSession.AUTO_ACKNOWLEDGE);
		topicPublisher = topicSession.createPublisher(topicSender);
		topicConnection.start();

		Topic topic = (Topic) context.lookup("topic/JMSServerReciever");
		topicSession.createSubscriber(topic).setMessageListener(this);

		Queue queue = new Queue();
		queue.start();

	}

	// getInit Context
	Context getContext() throws NamingException {
		Properties props = new Properties();
		props.setProperty("java.naming.factory.initial",
				"org.jnp.interfaces.NamingContextFactory");
		props.setProperty("java.naming.factory.url.pkgs", "org.jboss.naming");
		props.setProperty("java.naming.provider.url", "localhost:1099");
		return new InitialContext(props);
	}

	// Recive message
	@Override
	public void onMessage(Message message) {
		try {
			String mess = ((TextMessage) message).getText();
			curQueue.add(mess);
		} catch (JMSException e) {

		}
	}

	// Send message

	private void sendMessage(String message) {
		try {
			topicPublisher.publish(topicSession.createTextMessage(message));

		} catch (JMSException e) {
			e.printStackTrace();
		}

	}

	private Vector<Vector<String>> Split(String str) {
		Vector<Vector<String>> res = new Vector<Vector<String>>();
		String tmp = "";
		String header = "" + str.charAt(0);
		Vector<String> curLine = new Vector<String>();
		int i = 0;
		int length = str.length();
		for (; i < length; i++) {
			if (str.charAt(i) == '\n') {
				curLine.add(tmp);
				res.add(curLine);
				curLine = new Vector<String>();
				tmp = "";
				i++;
				break;
			}
			if (str.charAt(i) == ':') {
				curLine.add(tmp);
				tmp = "";
				continue;
			} else
				tmp += str.charAt(i);
		}

		if (header.equals("1")) {
			int l = Integer.parseInt(res.get(0).get(1));
			int cnt = 0;
			for (; i < length; i++) {
				if (str.charAt(i) == '\n') {
					curLine.add(tmp);
					res.add(curLine);
					curLine = new Vector<String>();
					tmp = "";
					cnt++;
					if (cnt == l) {
						i++;
						break;
					}
					continue;
				}
				if (str.charAt(i) == ':') {
					curLine.add(tmp);
					tmp = "";
					continue;
				} else
					tmp += str.charAt(i);
			}
			
			cnt = 1;
			while (true) {
				int pos = str.indexOf('\n', i);
				if (pos == -1) {
					res.get(cnt).addElement(str.substring(i));
					break;
				}
				res.get(cnt++).addElement(str.substring(i, pos));
				i = pos + 1;
			}
			
		} else {
			for (; i < length; i++) {
				if (str.charAt(i) == '\n') {
					curLine.add(tmp);
					res.add(curLine);
					curLine = new Vector<String>();
					tmp = "";
					continue;
				}
				if (str.charAt(i) == ':') {
					curLine.add(tmp);
					tmp = "";
					continue;
				} else
					tmp += str.charAt(i);
			}
			curLine.add(tmp);
			res.add(curLine);
		}
		return res;
	}
	
}
